﻿using System.Collections.Generic;
using System.Linq;
using Foxit.PDF;
using Foxit.PDF.IO;
using Foxit.PDF.PageElements;
using Sustainalytics.ESG.Entities;
using Sustainalytics.Reporting.Framework;
using System;
using Sustainalytics.Entities.RiskRatings;
using Foxit.PDF.Imaging;

namespace Sustainalytics.RiskRatings.Reporting.Charts
{
    public class RiskRating_BubbleChart : PageElement
    {
        public float Left { get; set; }
        public float Top { get; set; }
        public float Width { get; set; }
        public float Height { get; set; }
        public List<MaterialIssuePerformance> MaterialIssueDataPoints { get; set; }

        public RiskRating_BubbleChart(float left, float top, float width)
        {
            Left = left;
            Top = top;
            Width = width;
            Height = width - 30;
        }

        private Group Chart()
        {
            var pageElements = new Group();
            var leftOffset = 30.0f;
            var lineSize = 1f;
            var lineColor = RgbColor.Gray;
            var labelSize = 6f;
            float chartRootPointX = Left + leftOffset;
            float chartRootPointY = Top + Height;
            float maxValueY = 100;
            float maxValueX = 20;
            float pointWidthY = (Width - leftOffset) / maxValueY;
            float pointWidthX = (Width - leftOffset) / maxValueX;
            var imageFile = ReportHelper.GetFile("bubble.png");
            var sideEraserWidth = 30;
            var sideEraserColor = RgbColor.White;

            float left, top;

            float maxWeigth = (float)MaterialIssueDataPoints.OrderByDescending(point => point.FinalWeight).First().FinalWeight;
            float maxScale = 0.20f;

            // Add the chart bubbles
            foreach (MaterialIssuePerformance point in MaterialIssueDataPoints)
            {
                top = chartRootPointY - (maxValueY - (float)point.Management) * pointWidthY;
                left = chartRootPointX + (float)point.Exposure * pointWidthX;
                var image = ImageData.GetImage(imageFile);
                float scale = (float)point.FinalWeight * maxScale / maxWeigth;
                pageElements.Add(new Image(image, left - image.Width * scale / 2 - 1f, top - image.Height * scale / 2 + 3f, scale));
            }

            // Clear the sides with empty rectangles
            pageElements.Add(new Rectangle(chartRootPointX - sideEraserWidth, Top - sideEraserWidth, sideEraserWidth, Height + sideEraserWidth, sideEraserColor, sideEraserColor)); // left
            pageElements.Add(new Rectangle(chartRootPointX + Height, Top - sideEraserWidth, sideEraserWidth, Height + sideEraserWidth, sideEraserColor, sideEraserColor)); // right
            pageElements.Add(new Rectangle(chartRootPointX - sideEraserWidth, Top - sideEraserWidth, Height + sideEraserWidth * 2, sideEraserWidth, sideEraserColor, sideEraserColor)); // top
            pageElements.Add(new Rectangle(chartRootPointX - sideEraserWidth, chartRootPointY , Height + sideEraserWidth * 2, sideEraserWidth, sideEraserColor, sideEraserColor)); // bottom
            
            // Add the axis
            pageElements.Add(new Rectangle(chartRootPointX, Top, Height, Height, lineColor, lineSize));

            // Add the chart labels
            pageElements.Add(
                new Label("Management", Left + 15, chartRootPointY, Height, labelSize, Fonts.RobotoBold, labelSize, TextAlign.Center, RgbColor.Black)
                { Angle = -90 });
            pageElements.Add(
                new Label("Weak", Left + 20, chartRootPointY, Height, labelSize, Fonts.RobotoRegular, labelSize, TextAlign.Right, RgbColor.Black)
                { Angle = -90 });
            pageElements.Add(
                new Label("Strong", Left + 20, chartRootPointY, Height, labelSize, Fonts.RobotoRegular, labelSize, TextAlign.Left, RgbColor.Black)
                { Angle = -90 });
            pageElements.Add(
                new Label("Exposure", chartRootPointX, chartRootPointY + 10, Width - leftOffset, labelSize, Fonts.RobotoBold, labelSize, TextAlign.Center, RgbColor.Black));
            pageElements.Add(
                new Label("Low", chartRootPointX, chartRootPointY + 5, Width - leftOffset, labelSize, Fonts.RobotoRegular, labelSize, TextAlign.Left, RgbColor.Black));
            pageElements.Add(
                new Label("High", chartRootPointX, chartRootPointY + 5, Width - leftOffset, labelSize, Fonts.RobotoRegular, labelSize, TextAlign.Right, RgbColor.Black));

            // Add the chart labels that should be on top of the bubbles
            pageElements.Add(
            new Label("Negligible Risk", chartRootPointX + 5, chartRootPointY - 10, Width - leftOffset, labelSize, Fonts.RobotoRegular, labelSize, TextAlign.Left, RgbColor.Black));
            pageElements.Add(
                new Label("Severe Risk", chartRootPointX, Top + 5, Width - leftOffset - 5, labelSize, Fonts.RobotoRegular, labelSize, TextAlign.Right, RgbColor.Black));

            // Add the index on top of the bubbles
            float index = 1;
            foreach (MaterialIssuePerformance point in MaterialIssueDataPoints)
            {
                top = chartRootPointY - (maxValueY - (float)point.Management) * pointWidthY;
                left = chartRootPointX + (float)point.Exposure * pointWidthX;
                pageElements.Add(new Label(index++.ToString(), left - labelSize / 2, top, labelSize, labelSize, Fonts.RobotoRegular, labelSize, TextAlign.Left, RgbColor.Black));
            }

            return pageElements;
        }

        public override void Draw(PageWriter writer)
        {
            var chart = Chart();

            writer.Write_q_(true);
            chart.Draw(writer);
            writer.Write_Q(true);
        }
    }
}
